; ADAPT.ASM
; Beispiel fr ein adaptives Filter
; ELRAD DSP-Reihe; Holger Strauss, 02/96

LAENGE    EQU   16                    ; Filterlnge
NOISELVL  EQU   0.5                   ; Rauschpegel
K         EQU   0.02                  ; Schleifenverstrkung
MODSPEED  EQU   3000                  ; Modulationsperiode

          ORG   x:$10
daten     BSM   LAENGE,0              ; Filterzustnde
          ORG   x:$200
noisevalx DC    $123456               ; Startwert Rauschgenerator

          ORG   y:0
koeff     BSM   LAENGE,0              ; Filterkoeffizienten
          ORG   y:$200
noisevaly DC    $123456               ; Startwert Rauschgenerator

          INCLUDE 'init.asm'          ; Routinen einbinden
          move  #daten,r0             ; Zeiger auf Filterzustnde
          move  #LAENGE-1,m0          ; Pufferlnge - 1
          move  #koeff,r4             ; Zeiger auf Filterkoeffizienten
          move  #LAENGE-1,m4          ; Pufferlnge - 1
          move  #$100,r1              ; Zeiger auf Sinustabelle im ROM
          move  #$ff,m1               ; Lnge der Sinustabelle
          move  #0,r5                 ; Zhler fr Frequenzmodulation
          move  #MODSPEED,m5          ; Modulationsperiode
          move  #0,r6                 ; aktuelle Frequenz
          move  #64,m6                ; maximale Frequenz

          bset  #2,omr                ; Sinus-Tabelle (ROM) einblenden

loop      jset  #2,x:SSISR,*          ; auf nchsten Frame warten
          jclr  #2,x:SSISR,*

; Teil 1: Rauschen und Sinus mischen

          jsr   random                ; Zufallswert nach A
          move  a1,x0
          move  #NOISELVL,y0
          mpy   x0,y0,a               ; Rauschpegel einstellen

          jsr   sinus                 ; x0 = Sinuswert
          move  #1-NOISELVL,y0
          macr  x0,y0,a               ; Sinuspegel einstellen

          move  a,x:TX_BUFF_BASE      ; Signalgemisch links ausgeben
          move  a,x1                  ; und in x1 merken

; Teil 2: Prdiktionssignal berechnen und Fehler berechnen

          clr   a        x:(r0)+,x0  y:(r4)+,y0  ; FIR-Filter berechnen
          rep   m0
          mac   x0,y0,a  x:(r0)+,x0  y:(r4)+,y0
          macr  x0,y0,a  x1,b         ; A = Prdiktionswert
          sub   a,b                   ; B = Prdiktionsfehler

          move  a,x:TX_BUFF_BASE+1    ; rechts gefiltert ausgeben

; Teil 3: Filterkoeffizienten nachstellen

          move  #K,y1                 ; y1 = Schleifenverstrkung K
          move  b,x0                  ; x0 = Prdiktionsfehler e[n]
          mpy   x0,y1,b               ; b = K*e[n]
          move  b,y1                  ; y1 = b = K*e[n]

          do    #LAENGE,adaptloop
          move  y:(r4),a  x:(r0)+,x0  ; a = h_n[i], x0 = x_n[i]
          mac   x0,y1,a               ; a = h_n[i] + K*e[n]*x_n[i]
          move  a,y:(r4)+             ; a --> neuer Koeffizient h_n[i]
adaptloop
          move  x1,x:-(r0)            ; verzgerten Abtastwert einschreiben

          jmp   loop                  ; und wieder von vorne


; *** Unterroutine fuer weisses Rauschen ***

random    move  l:noisevalx,ba        ; alte Werte lesen
          lsl   a     #$1d872b,y1     ; shiften
          jcc   nicht_eor
          eor   y1,a                  ; Bits drehen
nicht_eor addr  a,b   a1,x:noisevalx
          move        b1,y:noisevaly
          rts


; *** Unterroutine fr Sinus-Sweep ***

sinus     move  (r5)+                 ; weiterzhlen
          move  r5,b
          tst   b                     ; Frequenz erhhen?
          jne   weiter                ; nein, dann weiter
          move  (r6)+                 ; Frequenz erhhen!
          move  r6,n1                 ; bertragen
weiter    nop                         ; Pipeline-Effekt
          move  y:(r1)+n1,x0          ; Sinustabelle auslesen
          rts

